package cn.jszhao.common.utils;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.asymmetric.SM2Engine;

import java.security.KeyPair;

/**
 * SM2加解密工具类
 *
 * @auth: 紫麒麟vip
 * @create: 2023/6/14 17:25
 * Description:
 */
public class SM2Utils {
    /**
     * 默认私钥
     */
    private final static String privateKey = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420151600199f22d0f1ce66042a9840b529b8f2684c4ba4401c80f9d2f57810c04ba00a06082a811ccf5501822da144034200041149b874ec2a110a9d583d86c904df2d8c15bab061288751c1ad267f7c63e73ca563ec6e194ae771d3a16cf70f424ffc1759eaf0a547ea4c1090bde6c7744286";
    /**
     * 默认公钥
     */
    private final static String publicKey = "3059301306072a8648ce3d020106082a811ccf5501822d034200041149b874ec2a110a9d583d86c904df2d8c15bab061288751c1ad267f7c63e73ca563ec6e194ae771d3a16cf70f424ffc1759eaf0a547ea4c1090bde6c7744286";

    /**
     * 使用默认公钥加密
     * @param plaintext 明文
     * @return 密文
     */
    public static String encrypt(String plaintext) {
        return encryptByPublicKey(plaintext, publicKey);
    }

    /**
     * 使用指定公钥加密
     * @param plaintext 明文
     * @param publicKey 公钥
     * @return 密文
     */
    public static String encryptByPublicKey(String plaintext, String publicKey) {
        if (StringUtils.isBlank(plaintext)) {
            return "";
        }
        SM2 sm2 = SmUtil.sm2(null, publicKey);
        sm2.setMode(SM2Engine.SM2Mode.C1C3C2);
        return sm2.encryptBcd(plaintext, KeyType.PublicKey);
    }


    /**
     * 使用默认私钥解密
     * @param encryptStr 密文
     * @return 明文
     */
    public static String decrypt(String encryptStr) {
        return decryptByPrivateKey(encryptStr, privateKey);
    }

    /**
     * 使用指定私钥解密
     * @param encryptStr 密文
     * @param privateKey 指定私钥
     * @return 明文
     */
    public static String decryptByPrivateKey(String encryptStr, String privateKey) {
        if (StringUtils.isBlank(encryptStr)) {
            return encryptStr;
        }
        SM2 sm2 = SmUtil.sm2(privateKey, null);
        sm2.setMode(SM2Engine.SM2Mode.C1C3C2);
        return sm2.decryptStr(encryptStr, KeyType.PrivateKey);
    }

    /**
     * 生成公、私密钥对
     *
     * @return 由私钥和公钥组成的二维字符串数组
     */
    public static String[] generateKey() {
        KeyPair pair = SecureUtil.generateKeyPair("SM2");
        byte[] privateKey = pair.getPrivate().getEncoded();
        byte[] publicKey = pair.getPublic().getEncoded();
        System.out.println("->" + CharsetUtil.defaultCharsetName());
        String privateStr = HexUtil.encodeHexStr(privateKey);
        String publicStr = HexUtil.encodeHexStr(publicKey);
        System.out.println("自定义私钥：" + privateStr);
        System.out.println("自定义公钥：" + publicStr);
        return new String[]{privateStr, publicStr};
    }

    public static void main(String[] args) {
        String text = "wangjing张三";

        //使用随机生成的密钥对加密或解密
        System.out.println("使用随机生成的密钥对加密或解密====开始");
        SM2 sm2 = SmUtil.sm2();
        // 公钥加密
        String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
        System.out.println("公钥加密结果：" + encryptStr);
        //私钥解密
        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
        System.out.println("私钥解密结果：" + decryptStr);
        System.out.println("使用随机生成的密钥对加密或解密====结束");


        //使用自定义密钥对加密或解密
        System.out.println("使用自定义密钥对加密或解密====开始");

        String[] key = generateKey();
        SM2 sm22 = SmUtil.sm2(key[0], key[1]);
        // 公钥加密
//        String encryptStr2 = sm22.encryptBcd(text, KeyType.PublicKey);
        String encryptStr2 = encrypt(text);
        System.out.println("公钥加密结果：" + encryptStr2);
        //私钥解密
//        String decryptStr2 = StrUtil.utf8Str(sm22.decryptFromBcd(encryptStr2, KeyType.PrivateKey));
        String decryptStr2 = decrypt(encryptStr2);
        System.out.println("私钥解密结果：" + decryptStr2);
        System.out.println("使用自定义密钥对加密或解密====结束");
    }
}
